#include "Server.h"
#include <QMessageBox>
#include <QTcpServer>
#include <QTcpSocket>
#include <QSignalMapper>
#include <QDebug>

using namespace Networking;

Server::Server(quint16 port) :
    m_port(port),
    m_players(),
    m_connections()
{
    qDebug() << "Server::Server(" << port << ")";
    m_serverSocket = new QTcpServer(this);

    if (!m_serverSocket->listen(QHostAddress::Any, port)) {
        QMessageBox::critical(0,
                              "Server Error",
                              "Unable to start the server:" + m_serverSocket->errorString());
        m_serverSocket->close();
        return;
    }
    connect(m_serverSocket, SIGNAL(newConnection()),
            this, SLOT(SlotProcessNewConnection()));
}

void Server::SlotProcessNewConnection()
{
    qDebug() << "void Server::SlotProcessNewConnection()";
    Connection* conn = new Connection(m_serverSocket->nextPendingConnection());

    conn->SlotSendData(m_playerlistMsg);
    connect(conn, SIGNAL(SignalNewMessage(const QString&, int)),
            this, SLOT(SlotDispatchMsg(const QString&)));

    connect(conn, SIGNAL(SignalConnectionLost()),
            this, SLOT(SlotDisconnect()));

    connect(this, SIGNAL(SignalSendMessage(const QString&)),
            conn, SLOT(SlotSendData(const QString&)));

    m_connections.push_back(ConnectionPtr(conn));

}

void Server::parseMessage(const QString& msg, int id)
{
    qDebug() << "parseMessage(" << msg << ")";
    Command  cmd = m_parser->ParseMessage(msg, id);
    if(cmd.Type() != Command::eUnknown)
        emit  SignalNewCommandReady(cmd);
}

void Server::SlotDispatchMsg(const QString& msg)
{
    ConnectionPtr conn((Connection*)sender());
    if( !isPlayer(conn) )
    {
        Command cmd = m_parser->ParseMessage(msg);
        if(cmd.Type() == Command::eReqSendNickname && m_playersNum < 8)
        {
            conn->SetDescriptor(++m_playersNum);
            m_players.push_back(conn);
            emit SignalNewCommandReady(cmd);
        }
    }
}

bool Server::isPlayer(ConnectionPtr conn) const
{
    return conn->Descriptor() != -1;
}

void Server::SlotGameStarted()
{
    m_serverSocket->close();
    ConnectionPtr conn;
    foreach(conn, m_connections)
    {
        conn->DisconnectFromHost();
    }
    foreach(conn, m_players)
    {
        connect(conn.data(), SIGNAL(SignalNewMessage(const QString&, int)),
                this , SLOT(parseMessage(QString,int)));
    }
}

void Server::SlotGameEnded()
{
    m_playerlistMsg.clear();
    m_serverSocket->listen();
    m_players.clear();
}

void Server::SlotPlayerlistUpdate(const QString& msg)
{
    m_playerlistMsg = msg;
    SlotBroadcastAll(m_playerlistMsg);
}

void Server::SlotBroadcastAll(const QString& msg)
{
    ConnectionPtr conn;
    foreach(conn, m_connections)
    {
        conn->SlotSendData(msg);
    }
    SlotBroadcast(msg);
}

void Server::SlotBroadcast(const QString& msg)
{
     ConnectionPtr pConn;
     foreach(pConn, m_players)
     {
         pConn->SlotSendData(msg);
     }
}

int Server::m_playersNum = 1;
